﻿using System;
using System.Collections.Generic;

namespace ExcelMerge;

public partial class MergeModel
{
    public List<CellDiffItem> OriginItems { get; }
    public List<CellDiffItem> SelfItems { get; }
    public List<CellDiffItem> OtherItems { get; }
    public int ColCount { get; }
    private Action<List<CellDiffItem>,List<Patch<CellDiffItem>>> ApplyMerge { get; }

    private int _stepIndex = 0;
    private List<MergeStep> _steps = new();
    private List<Patch<CellDiffItem>> _selfOriginPatches;
    private List<Patch<CellDiffItem>> _otherOriginPatches;
    
    private MergeStep _currentStep => _steps[_stepIndex];

    public MergeModel(
        List<CellDiffItem> originItems,
        List<Patch<CellDiffItem>> selfOriginPatches,
        List<Patch<CellDiffItem>> otherOriginPatches,
        List<Patch<CellDiffItem>> selfRemainPatches,
        List<Patch<CellDiffItem>> otherRemainPatches,
        List<Patch<CellDiffItem>> mergedPatches,
        Action<List<CellDiffItem>, List<Patch<CellDiffItem>>> applyMerge)
    {
        OriginItems = originItems;
        ApplyMerge = applyMerge;
        _selfOriginPatches = selfOriginPatches;
        _otherOriginPatches = otherOriginPatches;
        
        SelfItems = diff_match_patch<CellDiffItem>.patch_apply(selfOriginPatches, originItems,out _);
        OtherItems = diff_match_patch<CellDiffItem>.patch_apply(otherOriginPatches, originItems,out _);
        
        ColCount = Math.Max(GetMaxColCount(originItems),GetMaxColCount(SelfItems));
        ColCount = Math.Max(ColCount, GetMaxColCount(OtherItems));
        
        _steps.Add(new MergeStep(selfRemainPatches,otherRemainPatches,mergedPatches));
    }
    
    private int GetMaxColCount(List<CellDiffItem> items)
    {
        int max = -1;
        int count = 0;
        foreach (var item in items)
        {
            if (item.IsLineFeed())
            {
                max = Math.Max(max, count);
                count = 0;
                continue;
            }
            count++;
        }

        return max;
    }

    public void ManualMerge(bool useSelf)
    {
        if (!HasConflict())
        {
            throw new Exception("没有冲突，不需要手动合并");
        }

        if (_stepIndex < _steps.Count - 1)
        {
            _steps = _steps.Slice(0, _stepIndex + 1);
        }
        
        var mergedPatches = _currentStep.MergedPatches.Slice(0);
        int selfStartIndex;
        int otherStartIndex;
        if (useSelf)
        {
            mergedPatches.Add(_currentStep.SelfPatches[0]);
            selfStartIndex = 1;
            otherStartIndex = GetConflictCount(_currentStep.SelfPatches, _currentStep.OtherPatches);
        }
        else
        {
            mergedPatches.Add(_currentStep.OtherPatches[0]);
            otherStartIndex = 1;
            selfStartIndex = GetConflictCount(_currentStep.OtherPatches, _currentStep.SelfPatches);
        }
        
        var merge = diff_match_patch<CellDiffItem>.patch_try_merge(_currentStep.SelfPatches.Slice(selfStartIndex), _currentStep.OtherPatches.Slice(otherStartIndex));
        mergedPatches.AddRange(merge.mergedPatches);
        _steps.Add(new MergeStep(merge.selfRemainPatches, merge.otherRemainPatches, mergedPatches));
        _stepIndex++;
    }

    public void ManualMergeAll(bool useSelf)
    {
        if (useSelf)
        {
            _steps.Add(new (new(),new(),_selfOriginPatches.Slice(0)));
        }
        else
        {
            _steps.Add(new (new(),new(),_otherOriginPatches.Slice(0)));
        }
        _stepIndex++;
    }

    public bool HasConflict()
    {
        return _currentStep.HasConflict();
    }
    
    public void NextStep()
    {
        if (!HasNextStep())
        {
            throw new Exception("没有更多步骤");
        }

        _stepIndex++;
    }

    public List<CellDiffItem> GetMergedItems()
    {
        var items = diff_match_patch<CellDiffItem>.patch_apply(_currentStep.MergedPatches, OriginItems,out var index,!HasConflict());
        if (HasConflict())
        {
            for (int i = index; i < OriginItems.Count && i < _currentStep.SelfPatches[0].start && i < OtherItems.Count; i++)
            {
                items.Add(OriginItems[i]);
            }
        }
        
        return items;
    }

    public bool HasNextStep()
    {
        return _stepIndex < _steps.Count - 1;
    }

    public void LastStep()
    {
        if (!HasLastStep())
        {
            throw new Exception("没有上一步");
        }
        _stepIndex--;
    }

    public bool HasLastStep()
    {
        return _stepIndex > 0;
    }

    public void Apply()
    {
        if (HasConflict())
        {
            throw new Exception("有冲突，无法应用合并");
        }
        
        ApplyMerge.Invoke(OriginItems,_currentStep.MergedPatches);
    }

    private int GetConflictCount(List<Patch<CellDiffItem>> patches1, List<Patch<CellDiffItem>> patches2)
    {
        int count = 0;

        while (count < patches2.Count)
        {
            if (patches2[count].start <= patches1[0].start + patches1[0].deleteLength)
            {
                count++;
                continue;
            }

            break;
        }
        
        return count;
    }
}